package com.atom.module.mvvm.extren

import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.widget.TextView
import androidx.annotation.CheckResult
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate

@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
 fun TextView.afterTextChanges()= callbackFlow<AfterTextChangeEvent> {
    checkMainThread()
    val listener = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit

        override fun afterTextChanged(s: Editable) {
            trySend(AfterTextChangeEvent(view = this@afterTextChanges, editable = s))
        }
    }

    addTextChangedListener(listener)
    awaitClose { removeTextChangedListener(listener) }
}
    .conflate()
    .asInitialValueFlow {
        AfterTextChangeEvent(view = this@afterTextChanges, editable = editableText)
    }

 data class AfterTextChangeEvent(
     val view: TextView,
     val editable: Editable?
)

/**
 *
 *
 */
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
 fun TextView.beforeTextChanges()=
    callbackFlow<BeforeTextChangeEvent> {
        checkMainThread()
        val listener = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
                trySend(
                    BeforeTextChangeEvent(
                        view = this@beforeTextChanges,
                        text = s,
                        start = start,
                        count = count,
                        after = after
                    )
                )
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit

            override fun afterTextChanged(s: Editable) = Unit
        }

        addTextChangedListener(listener)
        awaitClose { removeTextChangedListener(listener) }
    }
        .conflate()
        .asInitialValueFlow {
            BeforeTextChangeEvent(
                view = this@beforeTextChanges,
                text = text,
                start = 0,
                count = 0,
                after = 0
            )
        }

 data class BeforeTextChangeEvent(
     val view: TextView,
     val text: CharSequence,
     val start: Int,
     val count: Int,
     val after: Int
)

/**
 *
 */
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
 fun TextView.editorActionEvents(handled: (EditorActionEvent) -> Boolean = { true }) =
    callbackFlow<EditorActionEvent> {
        checkMainThread()
        val listener = TextView.OnEditorActionListener { v, actionId, keyEvent ->
            val event = EditorActionEvent(
                view = v,
                actionId = actionId,
                keyEvent = keyEvent
            )
            if (handled(event)) {
                trySend(event)
                true
            } else {
                false
            }
        }
        setOnEditorActionListener(listener)
        awaitClose { setOnEditorActionListener(null) }
    }.conflate()

 data class EditorActionEvent(
     val view: TextView,
     val actionId: Int,
     val keyEvent: KeyEvent?
)

/**
 */

@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
 fun TextView.textChangeEvents()= callbackFlow<TextChangeEvent> {
    checkMainThread()
    val listener = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
            trySend(
                TextChangeEvent(
                    view = this@textChangeEvents,
                    text = s,
                    start = start,
                    before = before,
                    count = count
                )
            )
        }

        override fun afterTextChanged(s: Editable) = Unit
    }

    addTextChangedListener(listener)
    awaitClose { removeTextChangedListener(listener) }
}
    .conflate()
    .asInitialValueFlow {
        TextChangeEvent(
            view = this@textChangeEvents,
            text = text,
            start = 0,
            before = 0,
            count = 0
        )
    }

 data class TextChangeEvent(
     val view: TextView,
     val text: CharSequence,
     val start: Int,
     val before: Int,
     val count: Int
)

/**
 *
 */

@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
 fun TextView.textChanges() = callbackFlow<CharSequence> {
    checkMainThread()
    val listener = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
            trySend(s)
        }

        override fun afterTextChanged(s: Editable) = Unit
    }

    addTextChangedListener(listener)
    awaitClose { removeTextChangedListener(listener) }
}
    .conflate()
    .asInitialValueFlow { text }


